/***************************************************************************
                  object.h  -  description
                    -------------------
   begin           : Fri Jun 21 2002
   copyright        : (C) 2002 by Michiel Visser
   email           :
 ***************************************************************************/

/***************************************************************************
 *                                                 *
 *  This program is free software; you can redistribute it and/or modify  *
 *  it under the terms of the GNU General Public License as published by  *
 *  the Free Software Foundation; either version 2 of the License, or    *
 *  (at your option) any later version.                        *
 *                                                 *
 ***************************************************************************/

/*
Glossary of terms:

*selfish: different objects can share data until a subelement of one of them is referenced. That parent-object becomes detached (using makeEditable) and selfish at that moment. an object that is selfish can be edited, but should not be duplicated. Use persist function to 'un-selfish'
*persist: detaches object and children completely and removes 'selfishness' recursively

Remember: an object is not necessarily under GC. Example: x=?{1}; y=x![1];

*/

#ifndef OBJECT_H
#define OBJECT_H

#include "mstl.h"
#include "tyle.h"
#include "regexp.h"

using namespace MSTL;

int mcvtest();

namespace Sess
{
class Session;
class Type;
class ClosureBinding;

typedef Ptr<Type>::Share TypePtr;

typedef Ptr<ClosureBinding>::Share ClosureBindingPtr;
}

#define OBJ_SIZE 8

namespace Obj
{
using namespace Sess;

class Object;

typedef Ptr<Object,Behaviour<>::GC > ObjectGCPtr;

class OList: public List<ObjectGCPtr>
{
public:
	OList() {}
  OList(const OList &cpyfrom): List<ObjectGCPtr>(cpyfrom) {}
  OList(const OList &cpyfrom, int count): List<ObjectGCPtr>(cpyfrom,count) {}
	~OList();
};
typedef Ptr<OList>::Share OListPtr;
}

#include "expr_basic.h"
//DEFINE_ALLOCATOR_ON(Obj::ObjectGCPtr)

typedef GCAllocator<Obj::Object, OBJ_SIZE,256,2048,251> ObjectAllocator;

extern ObjectAllocator objectGC;

#define DEFINE_ALLOCATOR_ON(X)\
template<> inline void *reserveBytes<X::Type>(int num );\
template<> inline void freeBytes<X::Type>(void *v );

DEFINE_ALLOCATOR_ON(Obj::OList)
DEFINE_ALLOCATOR_ON(Expression::EList)
DEFINE_ALLOCATOR_ON(Obj::OListPtr)

//Used for object::Own pointer:
template<> inline void *reserveBytes<Obj::Object>(int num );
template<> inline void freeBytes<Obj::Object>(void *v );

namespace Obj
{
using namespace Expression;

struct StringPtr
{ String m_string;//anchor
  char *m_ptr;
  StringPtr(String s, char *begin): m_string(s), m_ptr(begin) {} 
  StringPtr(String s): m_string(s), m_ptr((char*)s) {} 
};

struct StringSegment: public StringPtr
{ int m_len;
  StringSegment(String s, char *begin, int length): StringPtr(s,begin), m_len(length) {} 
  StringSegment(String s): StringPtr(s), m_len(s.length()) {} 
};

class MapObject;
struct MapNode;
class ObjectHolderCP;

class Object;
class ObjectBase;

typedef struct
{
	int typeNum;
  int (*toInt )(const Object *_this);
  int (*hash  )(const Object *_this);
  int (*length)(const Object *_this);
  int (*compare   )(const Object *_this,Object *b);
  int (*objCompare)(const Object *_this, Object *b); //treats reference objects as comparable objects
	int (*strcmp)(Object *_this, const char *ptr, int len);
  String (*toTyle       )(const Object *_this);
  String (*constToString)(const Object *_this);
  OListPtr (*getConstList)(const Object *_this); // gets a list that we may not change
  OListPtr (*getCopiedList)(const Object *_this); // gets usable list
  OListPtr (*getEditableList)(Object *_this);
  float (*toFloat)(const Object *_this);
  EPtr (*makeExpr)(const Object *_this);
	bool (*containsRef)(const Object *_this);
	bool (*sub)(Object *_this, Object *o);
	bool (*div)(Object *_this, Object *o);
  bool (*subFromMap)(const Object *_this, MapObject &map);
  Object *(*index_i)(Object *_this, int i); // might return orphan
  Object *(*index)(Object *_this, Object *i);
  void (*indexCopy_i)(const Object *_this, int i, void *space); // fast version
	void (*apply)(const Object *_this, Expr *e, void *space);
	void (*applyToVoid)(const Object *_this, Expr *e);
	void (*evaluateToCopy)(const Object *_this, void *space);
	void (*evaluateToVoid)(const Object *_this);
  void (*GCPaintMyChildren)(const Object *_this);
  void (*toArray)(const Object *_this,OList::P array);
  void (*toStringList)(const Object *_this,List<StringSegment>::P &p);
	void (*destroy       )(Object *_this);
  void (*negate        )(Object *_this);
  void (*bitNot        )(Object *_this);
  void (*selectElements)(Object *_this,MapObject &selector, MapObject &output);
	void (*add    )(Object *_this, Object *o);
	void (*mul    )(Object *_this, Object *o);
	void (*prepend)(Object *_this, Object *o);
	void (*bitAnd )(Object *_this, Object *b);
	void (*bitOr  )(Object *_this, Object *b);
	void (*bitXor )(Object *_this, Object *b);
  void (*shiftLeft )(Object *_this, Object *o, void *space);
  void (*shiftRight)(Object *_this, Object *o, void *space);
  bool (*mod)(Object *_this, Object *_this);
  void (*insertAt)(Object *_this, Object *i, Object *obj);
  void (*removeAt)(Object *_this, Object *i, void *space);
  void (*actOnColumns)(Object *_this, OList::P resi, EPtr b);
  void (*findIndex)(Object *_this, Object *b, void *space);
	void (*duplicateIn)(const Object *_this,void *space);
	OListPtr (*getIterList)(Object *_this, TypePtr &strct,bool isCopy=true);
  void (*persist )(Object *_this);
} VTObject;

extern VTObject vtable_Char;
extern VTObject vtable_Expr;
extern VTObject vtable_ClosuredExpr;
extern VTObject vtable_Float;
extern VTObject vtable_Integer;
extern VTObject vtable_List;
extern VTObject vtable_Map;
extern VTObject vtable_Null;
extern VTObject vtable_Ref;
extern VTObject vtable_RegExp;
extern VTObject vtable_SelfishList;
extern VTObject vtable_SelfishMap;
extern VTObject vtable_String;
extern VTObject vtable_StringSegment;
extern VTObject vtable_SelfishString;

#define M_OBJ (((RefObject *)_this)->m_obj)
#define M_STRING (((StringObject *)_this)->m_string)
#define M_INT (((IntegerObject *)_this)->m_int)
#define M_FLOAT (((FloatObject *)_this)->m_float)
#define M_OBJECTS (((ListObject *)_this)->m_objects)
#define M_ROOTPTR (((MapObject *)_this)->m_rootPtr)
#define M_REGEXP (((RegExpObject *)_this)->m_expr)
#define M_CHAR (((CharObject *)_this)->m_char)
#define M_SEG (((StringSegmentObject *)_this)->m_seg)
#define M_E (((ExprObject *)_this)->m_e)
#define M_BINDING (((ClosuredExprObject *)_this)->m_binding)

#define NEW_OBJ (Object *)new (ao())

#define O_SEG ((StringSegmentObject *)_this)
#define O_LIST ((ListObject *)_this)
#define O_MAP ((MapObject *)_this)
#define O_STRING ((StringObject *)_this)

class ObjectBase
{
public:
	const VTObject *vtable;
	inline Object *operator &() const { return (Object *)this; }
	ObjectBase( const VTObject *_vtable ): vtable(_vtable) {}
  inline int getTypeNum() const { return vtable->typeNum; }
  inline String toTyle() const { return vtable->toTyle((Object *)this); }
  /*--misc*/
  inline static Object *allocate() { return (Object *)objectGC.alloc(); }
  /*--conversion--*/
  inline int typeDiff(const Object *b) const;
  inline bool operator==(Object *o) const { return objCompare(o)==0; } 
  inline bool operator!=(Object *o) const { return objCompare(o)!=0; } 
  inline OListPtr getConstList() const { return vtable->getConstList((Object *)this); } // gets a list that we may not change
  inline OListPtr getEditableList() { return vtable->getEditableList((Object *)this); }
  inline void persist() { if (vtable->persist) vtable->persist((Object *)this); }
  Object *toArrayObject() const;
  String toString() const;
  Object * value() const;
  inline void evaluateToVoid();
  //Object * evaluateToOriginal();
  inline void evaluateToCopy(void *space) { vtable->evaluateToCopy((Object *)this, space); }
  //Object * applyToOriginal();
  Object * deReference() const; // todo: make non-inlines inline again!
  void addToMap(MapObject &map) const;
  void set(Object *o);
  inline void valueCopy(void *space) const;
  inline OListPtr getCopiedList() const { return vtable->getCopiedList((Object *)this); } // gets usable list
  inline int  toInt() const { return vtable->toInt((Object *)this); }
  inline int  hash() const { return vtable->hash((Object *)this); }
  inline int  compare(Object *b) const { return vtable->compare((Object *)this,b); }
  inline int  objCompare(Object *b) const { return vtable->objCompare((Object *)this,b); } //treats reference objects as comparable objects
  inline float toFloat() const { return vtable->toFloat((Object *)this); }
  inline String constToString() const { return vtable->constToString((Object *)this); }
  inline void selectElements(MapObject &selector, MapObject &output) { return vtable->selectElements((Object *)this,selector,output); }
  inline void toArray(OList::P array) const { return vtable->toArray((Object *)this,array); }
  inline void toStringList(List<StringSegment>::P &p) const { return vtable->toStringList((Object *)this,p); }
  inline void duplicateIn(void *space) const { vtable->duplicateIn((Object *)this,space); }
	inline void apply(Expr *e, void *space) const { vtable->apply((Object *)this,e,space); }
	inline void applyToVoid(Expr *e) const { vtable->applyToVoid((Object *)this,e); }

#define BINFUNC(x) void x(Object *o) { vtable->x((Object *)this,o); }
  BINFUNC(add) BINFUNC(mul) BINFUNC(prepend)
#undef BINFUNC
#define BINFUNC(x) bool x(Object *o)  { return vtable->x((Object *)this,o); }
	BINFUNC(sub); BINFUNC(div);
#undef BINFUNC
  inline bool mod(Object *o) {  return vtable->mod((Object *)this, o); }
  inline Object * index(int i) { return vtable->index_i((Object *)this, i); } // might return orphan
  inline Object * index(Object *i) { return vtable->index((Object *)this, i); }
  inline void indexCopy(int i, void *space) const {  vtable->indexCopy_i((Object *)this,i,space); } // fast version
  void indexCopy(Object *i, void *space) const;
  inline void shiftLeft(Object *o, void *space) {  vtable->shiftLeft((Object *)this,o,space); }
  inline void shiftRight(Object *o, void *space) { vtable->shiftRight((Object *)this,o,space); }
  inline void insertAt(Object *i, Object *obj) { vtable->insertAt((Object *)this,i,obj); }
  inline void removeAt(Object *i, void *space) { vtable->removeAt((Object *)this,i,space); }
  inline EPtr makeExpr() const { return vtable->makeExpr((Object *)this); }
	inline bool containsRef() const { return vtable->containsRef((Object *)this); }
  inline bool subFromMap(MapObject &map) const { return vtable->subFromMap((Object *)this,map); }
  inline void actOnColumns(OList::P resi, EPtr b) { vtable->actOnColumns((Object *)this,resi,b); }
  inline void negate() { vtable->negate((Object *)this); }
  inline void bitNot() { vtable->bitNot((Object *)this); }
	inline void bitAnd(Object *b) { vtable->bitAnd((Object *)this,b); }
	inline void bitOr(Object *b) { vtable->bitOr((Object *)this,b); }
	inline void bitXor(Object *b) { vtable->bitXor((Object *)this,b); }
	inline int strcmp(const char *ptr, int len) { return vtable->strcmp((Object *)this,ptr,len); }
  inline int length() const  { return vtable->length((Object *)this); }
  inline void findIndex(Object *b, void *space) { vtable->findIndex((Object *)this,b,space); }
	inline OListPtr getIterList(TypePtr &strct,bool isCopy=true) { return vtable->getIterList((Object *)this,strct,isCopy); }
  inline void GCPaintMyChildren() const { vtable->GCPaintMyChildren((Object *)this); }

  int toShiftNumber(const Object *o, int l) const;
  inline Object *copy() const;
  inline const OList &getList() const;
  inline OList &getEditableListQuick();
	inline ~ObjectBase() {}
};

class Object: public ObjectBase
{
	Object(): ObjectBase(0) {}
public:
  typedef ObjectGCPtr GC;
  typedef Ptr<Object>::Own Own;
  typedef InheritanceHolder<Object,OBJ_SIZE> Holder;
	typedef ObjectHolderCP HolderCP;
  /*--standard functions--*/
  //inline void copy(void *space) const;
  inline ~Object() { vtable->destroy(this); }
  static void GCStartPaint();
  void GCunuse();
};

inline Object *ao() { return Object::allocate(); } //short way of writing
inline Object *ObjectBase::copy() const { void *m;duplicateIn(m=ao()); return (Object *)m;}
inline int ObjectBase::toShiftNumber(const Object *o, int l) const
{ int i=o->toInt();
	if (i<0) { i+=l; if (i<0) i=0; }
	else if (i>l) { i=l; }
	return i;
}
inline void ObjectBase::evaluateToVoid() { vtable->evaluateToVoid((Object *)this); }
inline void ObjectBase::valueCopy(void *space) const { value()->duplicateIn(space); }

class NullObject: public ObjectBase
{
public:
  NullObject(): ObjectBase(&vtable_Null) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("NullObject(): ");_TRACE;) }
  static Object *obj() { return (Object *)new (ao()) NullObject(); }
	inline ~NullObject() {} //non-virtual
};
//todo: check if iter is checked in painting
class RefObject: public ObjectBase
{
public:
	Object::GC m_obj;
  RefObject(Object * o): ObjectBase(&vtable_Ref), m_obj(o) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("RefObject(%p): ",o);_TRACE;) } 
  RefObject(const RefObject &o): ObjectBase(&vtable_Ref), m_obj(o.m_obj) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("RefObject(copy: %p): ",(Object *)m_obj);_TRACE;) } 
	inline ~RefObject() {} //non-virtual
};


class StringObject: public ObjectBase
{
public:
  String m_string;
  StringObject(const StringObject &copyFrom, VTObject *vt=&vtable_String): ObjectBase(vt), m_string(copyFrom.m_string) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("StringObject(Copy: %.10s): ",(char *)m_string);_TRACE;)}
  StringObject(const String &s, VTObject *vt=&vtable_String): ObjectBase(vt), m_string(s) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("StringObject(%.10s): ",(char *)m_string);_TRACE;)}
  StringObject(const char *s, VTObject *vt=&vtable_String): ObjectBase(vt), m_string(s) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("StringObject(%.10s): ",(char *)m_string);_TRACE;) }
  StringObject(const char *s,int len, VTObject *vt=&vtable_String): ObjectBase(vt), m_string(s,len) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("StringObject(%.10s): ",(char *)m_string);_TRACE;)}
	inline ~StringObject() {} //non-virtual
};


class SelfishStringObject: public StringObject
{
public:
	SelfishStringObject( String s): StringObject(s,&vtable_SelfishString) {}
	SelfishStringObject (const SelfishStringObject &copyFrom): StringObject(copyFrom,&vtable_SelfishString) {}
	inline ~SelfishStringObject() {} // non-virtual
};

class IntegerObject: public ObjectBase
{
public:
  int m_int; 
  IntegerObject(const IntegerObject &copyFrom): ObjectBase(&vtable_Integer), m_int(copyFrom.m_int) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("IntegerObject(Copy: %i): ", m_int);_TRACE;) }
  IntegerObject(int i): ObjectBase(&vtable_Integer), m_int(i) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("IntegerObject(%i): ", m_int);_TRACE;)}
	inline ~IntegerObject() {} //non-virtual
};

class FloatObject: public ObjectBase
{
public:
  float m_float;
  FloatObject(const FloatObject &copyFrom): ObjectBase(&vtable_Float), m_float(copyFrom.m_float) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("FloatObject(Copy: %f): ",m_float);_TRACE;)}
  FloatObject(float f):ObjectBase(&vtable_Float), m_float(f) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("FloatObject(%f): ",m_float);_TRACE;)}
	inline ~FloatObject() {} //non-virtual
};

class ListObject: public ObjectBase
{
public:
  inline static void copyElements(OList &l)// this is not the same as detaching, because original elements are not deleted/GC'ed
  { FOREACH(OList, l, i) 
    { Object *o=(*i)->copy();
      i->blindset(o);
    }
  }
  OListPtr m_objects;
  OList &operator *() { return *m_objects; }
  ListObject(VTObject *vt=&vtable_List): ObjectBase(vt) { new (m_objects) OList(); IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ListObject(): ");_TRACE;) }
  ListObject(OList &m, VTObject *vt=&vtable_List): ObjectBase(vt) {  new (m_objects) OList(); m_objects->take(m); IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ListObject({...}): ");_TRACE;) }
  ListObject(OListPtr m, VTObject *vt=&vtable_List): ObjectBase(vt) {  m_objects=m; IF_VERBOSE_OLT( _TV(p,this); _PRINTF("ListObject({...}): ");_TRACE;) }
  ListObject(const ListObject &copyFrom, VTObject *vt=&vtable_List): ObjectBase(vt) {  m_objects = copyFrom.m_objects; IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ListObject(Copy of: %p): ",&copyFrom);_TRACE;) }
	void makeEditable();
	inline ~ListObject() {} //non-virtual
};

class SelfishListObject: public ListObject
{
public:
	SelfishListObject( OListPtr l): ListObject(l, &vtable_SelfishList) {}
	SelfishListObject (const SelfishListObject &copyFrom): ListObject(copyFrom, &vtable_SelfishList) {}
	inline ~SelfishListObject() {} // non-virtual
};

struct EmptyMapNode
{
  typedef Ptr<MapNode>::Own P;
  P m_left, m_right;
	EmptyMapNode(const EmptyMapNode &copyFrom): m_left(copyFrom.m_left), m_right(copyFrom.m_right) {}
	EmptyMapNode() {}
};

struct MapNode: public EmptyMapNode
{ 
  char m_keySpace[OBJ_SIZE];
  Object::GC m_data;
  //not necessary: Object *key() const { Object *o; ((Object *)m_keySpace)->duplicateIn(ao(o)); return o; }
  Object *key() const { return (Object *)m_keySpace; }
  MapNode() {*(int *)m_keySpace=0;} // for header
  MapNode(const MapNode &copyFrom):EmptyMapNode(copyFrom) { copyFrom.key()->duplicateIn((void *)m_keySpace); m_data.blindset(copyFrom.m_data->copy()); } 
  MapNode(Object *k, Object *d): m_data(d) { k->duplicateIn((void *)m_keySpace); }
  ~MapNode();
};

class MapObject: public ObjectBase // {:hoi=>daar, piep=>hallo}
{
public:
	typedef Ptr<MapNode::P>::Share RootPtr;
  mutable RootPtr m_rootPtr;
  MapObject(VTObject *vt=&vtable_Map): ObjectBase(vt) { new (m_rootPtr) MapNode::P(); IF_VERBOSE_OLT(_TV(p,this); _PRINTF("MapObject(): ");_TRACE;) }
  MapObject(const MapObject &copyFrom, VTObject *vt=&vtable_Map): ObjectBase(vt) { m_rootPtr = copyFrom.m_rootPtr; IF_VERBOSE_OLT(_TV(p,this); _PRINTF("MapObject(copy: %p): ",&copyFrom);_TRACE;) }
  MapObject(RootPtr r, VTObject *vt=&vtable_Map): ObjectBase(vt) {  m_rootPtr=r; IF_VERBOSE_OLT( _TV(p,this); _PRINTF("MapObject({:...}): ");_TRACE;) }
	~MapObject(); //non-virtual
  void splay(const Object *key) const;
	void erase();
	void makeEditable() {	m_rootPtr.detach(); /* copies all elements */}
  inline Object * getOptionalData(Object *key) const
  { if (!*m_rootPtr) return 0;
    splay(key);
    if ((*m_rootPtr)->key()->objCompare(key)!=0) return 0;
    return (*m_rootPtr)->m_data;
  }
  // map +={: a=>b, c=>d :} {:a=>b,b=>c}
  // map[hoi]: get
  // (map:+=hoi) = obj // add or replace
  // (map:-=hoi) // remove
};

class SelfishMapObject: public MapObject
{
public:
	SelfishMapObject ( RootPtr r): MapObject(r, &vtable_SelfishMap) {}
	SelfishMapObject (const SelfishMapObject &copyFrom): MapObject(copyFrom, &vtable_SelfishMap) {}
	inline ~SelfishMapObject() {} //non-virtual
};

#define FOREACHM_DIR(MAP,EXPR,A,B) \
{ List<MapNode *>parents; \
  MapNode *p=*MAP m_rootPtr; \
  while (p) \
  { while (!!p->A) { parents.prepend(p); p=p->A; } \
    for(;;) \
    { { EXPR } \
      p=p->B; \
      if (!!p) break; \
      if (!parents) { p = 0; break; } \
      p=*parents; \
      parents.removeone(); \
    } \
  } \
}

#define FOREACHM(MAP,EXPR) FOREACHM_DIR(MAP,EXPR,m_left,m_right)
#define FOREACHM_BACK(MAP,EXPR) FOREACHM_DIR(MAP,EXPR,m_right,m_left)

class RegExpObject: public ObjectBase // `.*`imo
{
public:
  Ptr<RE::Expr>::Share m_expr;
  RegExpObject(unsigned char *p, int len, char mask): ObjectBase(&vtable_RegExp) { new (m_expr) RE::Expr(p,len,mask); IF_VERBOSE_OLT(_TV(p,this); _PRINTF("RegExpObject(...): ");_TRACE;) }
  void parse() { m_expr->parse(); }
  RegExpObject(const RegExpObject &copyFrom): ObjectBase(&vtable_RegExp) { m_expr=copyFrom.m_expr; IF_VERBOSE_OLT(_TV(p,this); _PRINTF("RefExpObject(copy): ");_TRACE;) }
	inline ~RegExpObject() {} //non-virtual
};

#ifndef NO_TEMP_OBJECTS
#define IF_TEMP_OBJECTS(...) __VA_ARGS__


class CharObject: public ObjectBase // temporary object
{
public:
  Ptr<StringPtr>::Own m_char;
  CharObject(String s, int index): ObjectBase(&vtable_Char), m_char(new StringPtr(s,(char *)s+index)) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("CharObject(%c): ",s[index]);_TRACE;) }
  CharObject(String s, char *c): ObjectBase(&vtable_Char), m_char(new StringPtr(s,c)) {IF_VERBOSE_OLT(_TV(p,this); _PRINTF("CharObject(%c): ",*c);_TRACE;) }
	inline ~CharObject() {} //non-virtual
};
#else
#define IF_TEMP_OBJECTS(...)
#endif

class StringSegmentObject: public ObjectBase // temporary object
{
public:
  Ptr<StringSegment>::Own m_seg;
  StringSegmentObject(String s, char *beg, int len=1): ObjectBase(&vtable_StringSegment), m_seg (new StringSegment(s,beg,len)) {}
  inline char *str() const { return m_seg->m_ptr; }
  void convertToString(String s);
  void convertToString();
	inline ~StringSegmentObject() {} //non-virtual
};

inline const OList &ObjectBase::getList() const
{	return *((ListObject *)this)->m_objects;
}

inline OList &ObjectBase::getEditableListQuick()
{	((ListObject *)this)->makeEditable();
	return *(((ListObject *)this)->m_objects);
}

inline int ObjectBase::typeDiff(const Object *b) const { return getTypeNum()-b->getTypeNum(); }
	
class ExprObject: public ObjectBase
{
public:
  EPtr m_e;
  ExprObject(EPtr to);
	inline ~ExprObject() {} //non-virtual
};

class ClosuredExprObject: public ObjectBase
{
	//invariant: m_e must point to ClosureBindingExpr
public:
	ClosureBindingPtr m_binding;
  ClosuredExprObject(ClosureBindingPtr binding);
	ClosuredExprObject(const ClosuredExprObject &copyFrom);
	inline ~ClosuredExprObject() {} //non-virtual
};

} // namespace obj

#ifdef MEMDEBUG_MALLOC
void *ireserveBytes(int num, char *name);
void ifreeBytes(void *v, char *name);
#define USE_ALLOCATOR_ON(X)\
template<> inline void *reserveBytes<X::Type>(int num ) { return ireserveBytes(num,#X); }\
template<> inline void freeBytes<X::Type>(void *v ) { ifreeBytes(v,#X); }
#else

//typedef Ptr<Obj::ExprObject>::Share::Dynamic::Type allocatorElem; //sizeof(allocatorElem)==12

extern BasicAllocator<8,256,2048> allocator;
/*
#define USE_ALLOCATOR_ON(X)\
template<> inline void *reserveBytes<X::Type>(int num ) { return mstl_alloc(sizeof(allocatorElem)); }\
template<> inline void freeBytes<X::Type>(void *v ) { mstl_free(v); }
*/
#define USE_ALLOCATOR_ON(X)\
template<> inline void *reserveBytes<X::Type>(int num ) { return allocator.alloc(); }\
template<> inline void freeBytes<X::Type>(void *v ) { allocator.free(v); }

#endif

USE_ALLOCATOR_ON(Obj::OList)
USE_ALLOCATOR_ON(EList)
USE_ALLOCATOR_ON(Obj::OListPtr)
USE_ALLOCATOR_ON(List<const Obj::Object *>)

template<> inline void *reserveBytes<Obj::Object>(int num ) { return objectGC.alloc(); }
template<> inline void freeBytes<Obj::Object>(void *v ) { /*///_TV(p,v,"Free: ")*/ objectGC.free(v); }

#endif // FILEXXX_H
